package com.kkb.order.controller;

import com.kkb.order.client.PayClient;
import com.kkb.order.service.OrderService;
import entity.Payment;
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.ExecutionException;

@RestController
@Slf4j
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient disoveryClient;

    @Autowired
    private LoadBalancerClient loadBalancerClient;


    /**
     * 通过discovery client,根据spring.application.name来获取服务
     * @param id
     * @return
     */
    @GetMapping("/order/{id}")
    //熔断
//    @CircuitBreaker(name = "backendA", fallbackMethod = "myFallback")
    //注意name="backendA"和name="backendD"效果相同，当找不到配置的backendD熔断器，使⽤默认熔断器配置，即为"default"。
//    @CircuitBreaker(name = "backendA", fallbackMethod = "myFallback")
//    @CircuitBreaker(name = "backendB", fallbackMethod = "myFallback")//测试慢调用
    //隔离
    //信号量隔离,线程池隔离见service
//    @Bulkhead(name = "backendA", fallbackMethod = "myFallback", type = Bulkhead.Type.SEMAPHORE)
//    @Bulkhead(name = "backendB", fallbackMethod = "myFallback", type = Bulkhead.Type.SEMAPHORE)
    //限流
    @RateLimiter(name = "backendA", fallbackMethod = "myFallback")
    public ResponseEntity<Payment> doOrder(@PathVariable("id") Integer id) throws InterruptedException {
        log.info("*** entered order controller ***");
        Thread.sleep(10000L); //阻塞10秒，已测试慢调⽤⽐例熔断
        String url = "";
        //注意，这里实际上是根据spring.application.name来获取的实例
        List<ServiceInstance> instances = disoveryClient.getInstances("eureka-pay");
//        List<ServiceInstance> instances = disoveryClient.getInstances("pay");
        ServiceInstance serviceInstance = instances.get(0);
        url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/pay/" + id;
        url = "http://eureka-pay/pay/" + id;//通过名字"eyreka-pay"获取服务调用
        Payment payment = restTemplate.getForObject(url, Payment.class);
        log.info("=== exited order controller ===");

        return ResponseEntity.ok(payment);
    }

//    @Autowired
//    private OrderService orderService;
//
//    @GetMapping("/order/{id}")
//    public ResponseEntity<Payment> doOrderThreadWay(@PathVariable("id") Integer id) throws InterruptedException, ExecutionException {
//        return ResponseEntity.ok(orderService.getPay().get());
//    }

    /**
     * 通过loaderbalancer来调用服务
     * @return
     */
    @GetMapping("/test-loadbalancerclient")
    public String testLoaderBalancerClient(){
        ServiceInstance serviceInstance = loadBalancerClient.choose("eureka-pay");
        return serviceInstance.getHost() + "/" + serviceInstance.getPort();
    }

    @Autowired
    private PayClient payClient;

    @RequestMapping("/feign/order/{id}")
    public ResponseEntity<Payment> doFeignOrder(@PathVariable("id") Integer id){
        ResponseEntity<Payment> responseEntity = payClient.doPayFeign(id);
        return responseEntity;
    }

    public ResponseEntity<Payment> myFallback(Integer id, Throwable throwable){
        Payment payment = new Payment(id, "fallback....");
        System.out.println(payment);
        return new ResponseEntity<>(payment, HttpStatus.BAD_REQUEST);
    }
}
